//命名管道(FIFO):write
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
/*
底层原理：
    1)文件系统中的特殊文件(mkfifo() 创建)此时并没有在内核区生成一个管道，当使用系统调用函数open 函数打来这个管道文件的时候，
    才会触发在内核生成一个管道(内核维护内存缓冲区), 用于进程间通信
    2)通过文件路径访问,不同进程之间的通信通过这个fifo文件确定操作同一块内核缓冲区，完成通信功能。
使用场景：
    1)无亲缘关系进程间通信
    2)客户端/服务器模型
优点：
    1)支持任意进程间通信
    2)文件系统可见
    3)保留管道语义
缺点：
    1)仍为单向通信
    2)性能低于匿名管道
    3)需要文件系统权限管理

注意事项：
    打开时可能阻塞（需正确处理 O_NONBLOCK）
    多个读写者需要额外同步
    删除文件不会影响已打开的 FIFO
*/

/*
    阻塞原因：FIFO 的打开和写入机制
    O_WRONLY 模式阻塞：当写进程以O_WRONLY模式打开 FIFO 时，若没有读进程已打开该 FIFO，写进程会阻塞直到有读进程打开它。
    内核机制：FIFO 需要至少一个读端和一个写端才能进行数据传输，若写端先打开，内核会等待读端连接。
*/

// 自定义 SIGPIPE 信号处理函数
void sigpipe_handler(int signum) {
    printf("Caught SIGPIPE signal, write operation failed due to broken pipe.\n");
}

int main(int argc, char *argv[]) {
    int fd;
    const char* fifo_path = "/tmp/myfifo";

    // 注册 SIGPIPE 信号处理函数
    signal(SIGPIPE, sigpipe_handler);

    // 创建命名管道（若不存在）
    if (mkfifo(fifo_path, 0755) == -1) {
        if (errno != EEXIST) {  // 忽略已存在的错误
            perror("mkfifo");
            return 1;
        }
    }

    //fd = open(fifo_path, O_WRONLY);             // 以写模式打开, 阻塞模式
    fd = open(fifo_path, O_WRONLY | O_NONBLOCK);  // 以写模式打开，非阻塞模式, 如果没有读端去读取，open会报错返回,需要先执行读端程序
    if (fd == -1) {
        perror("open");
        return 1;
    }
    
    char buf[1024];
    while(1){
        sleep(1);
        memset(buf, 0, sizeof(buf));
        scanf("%s", buf);
        int len = strlen(buf) + 1;
        ssize_t write_result  = write(fd, buf, len);
        if (write_result == -1) {
            perror("write():"); //管道破裂，失去了读端
            break;
        } else {
            printf("Write %zd bytes successfully.\n", write_result);
        }
    }
    close(fd);
    printf("write_fifo exit()\n");
    return 0;
}
